package com.wechat.dao.impl;

import com.wechat.dao.CommonDao;
import com.wechat.utils.beans.Pager;
import org.hibernate.*;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.sql.DataSource;
import java.io.Serializable;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class CommonDaoImpl implements CommonDao {

    @Autowired
    @Qualifier("sessionFactory")
    private SessionFactory sessionFactory;

    public Session getSession() {
        return sessionFactory.getCurrentSession();
    }


    private JdbcTemplate jdbcTemplate;
    @Autowired
    public void setJdbcTemplate(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Override
    public <T extends Serializable> T save(T model) {
        getSession().save(model);
        return model;
    }
    @Override
    public <T extends Serializable> void saveOrUpdate(T model) {
        getSession().saveOrUpdate(model);
        
    }
    @Override
    public <T extends Serializable> void update(T model) {
        getSession().update(model);
    }
    @Override
    public <T extends Serializable> void merge(T model) {
        getSession().merge(model);
    }
    @Override
    public <T extends Serializable, PK extends Serializable> void delete(Class<T> entityClass, PK id) {
        getSession().delete(get(entityClass, id));
    }
    @Override
    public <T extends Serializable> void deleteObject(T model) {
        getSession().delete(model);
    }
    @Override
    public <T extends Serializable, PK extends Serializable> T get(Class<T> entityClass, PK id) {
        return (T) getSession().get(entityClass, id);
        
    }
    @Override
    public <T extends Serializable> int countAll(Class<T> entityClass) {
        Criteria criteria = getSession().createCriteria(entityClass);
        criteria.setProjection(Projections.rowCount());
        return ((Long) criteria.uniqueResult()).intValue();
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T extends Serializable> List<T> listAll(Class<T> entityClass) {
//        Criteria criteria = getSession().createCriteria(entityClass);
//        criteria.setProjection(Projections.rowCount());
        String hql="from "+entityClass.getSimpleName();
       return findParamListByHQL(hql);
//        return criteria.list();
    }


    @Override
    public int countSqlQueryResult(String sql, Object... values) {
        String fromClause = sql.substring(sql.indexOf("from"));
        String countSql = "select count(0) " + fromClause;
        SQLQuery query = createSQLQuery(countSql, values);
        return ((BigInteger) query.uniqueResult()).intValue();
    }

    @Override
    public int countHqlQueryResult(String hql, Object... values) {
        String fromClause = hql.substring(hql.indexOf("from"));
        String countHql = "select count(*) " + fromClause;
        Query query = createQuery(countHql, values);
        return ((Long) query.uniqueResult()).intValue();
    }

    @Override
    public <T extends Serializable> List<T> findParamListByHQL(String hql, Object... values) {
        Query query = createQuery(hql, values);
        List<T> objArrayList = query.list();
        return objArrayList;
    }

    @Override
    public <T extends Serializable> T findByHQL(String hql, Object... values) {
        Query query = createQuery(hql, values);
        query.setFirstResult(0);
        query.setMaxResults(1);

        List<T> list = query.list();
        if (list.size() > 0)
            return list.get(0);
        return null;
    }


    /**
     * 通过属性查询唯一结果
     *
     * @param entityClass
     * @param propertyName 属性名
     * @param value        属性值
     * @return
     */
    @Override
    public <T extends Serializable> T findUniqueByProperty(Class<T> entityClass, String propertyName, Object value) {
        Assert.hasText(propertyName);
        if (value != null) {
            return (T) createCriteria(entityClass, Restrictions.eq(propertyName, value)).uniqueResult();
        } else {
            return (T) createCriteria(entityClass, Restrictions.isNull(propertyName)).uniqueResult();
        }
    }

    /**
     * 通过SQL查询结果集
     *
     * @param sqlString
     * @param values
     * @return
     */
    @Override
    public <T extends Serializable> List<T> findListBySQL(Class<T> entityClass,String sqlString, Object... values) {
        return findListBySQL(entityClass,0, Pager.DEFAULT_SIZE, sqlString, values);
    }


    /**
     * 通过sql语句查询结果集
     *
     * @param fromIndex 起始索引
     * @param size      需要获取的结果数
     * @param sqlString 实体示例
     * @param values    排除在外的属性列表
     * @return
     */
    @Override
    public <T extends Serializable> List<T> findListBySQL(Class<T> entityClass,int fromIndex, int size, String sqlString, Object... values) {
        SQLQuery sqlQuery = createSQLQuery(sqlString, values).addEntity(entityClass);
        sqlQuery.setFirstResult(fromIndex);
        sqlQuery.setMaxResults(size);
        return sqlQuery.list();
    }

    /**
     * 使用sql根据数据
     *
     * @param sql 更新的sql语句
     */
    @Override
    public void updateBySql(String sql) {
        jdbcTemplate.execute(sql);
    }

    @Override
    public <T extends Serializable> Pager<T> findByHQL(int pageNo, int pageSize, String hql, Object... values) {
        Pager<T> pager = new Pager<T>(pageNo, pageSize);
        return findByHQL(pager, hql, values);
    }

    @Override
    public <T extends Serializable> Pager<T> findByHQL(int pageNo, int pageSize, String hql, List<Object> valueList) {
        Object[] objArray = new Object[valueList.size()];
        for (int i = 0; i < valueList.size(); i++) {
            objArray[i] = valueList.get(i);
        }
        return findByHQL(pageNo, pageSize, hql, objArray);
    }

    /**
     * 根据HQL语句进行查询，并返回Pager对象
     *
     * @param pager  以pager封装的参数，主要取其中的页码和每页显示数来进行查询
     * @param hql    hql语句
     * @param values 参数值
     * @return
     */
    @Override
    public <T extends Serializable> Pager<T> findByHQL(Pager<T> pager, String hql, Object... values) {
        Assert.notNull(pager);

        pager.setTotalCount(countQueryResult(hql, values));
        Query query = createQuery(hql, values);
        query.setFirstResult(pager.getFirstIndex());
        query.setMaxResults(pager.getPageSize());
        @SuppressWarnings("rawtypes")
        List list = query.list();
        pager.setList(list);
        return pager;
    }



    @Override
    public List<Map<String, Object>> findByJdbcSql(String sql, Object... args) {
        final List<Map<String, Object>> list=new ArrayList<Map<String, Object>>();
        jdbcTemplate.query(sql, new RowMapper<Object>() {
            @Override
            public Object mapRow(ResultSet rs, int i) throws SQLException {
                ResultSetMetaData rsmd = rs.getMetaData();

                int columnCount = rsmd.getColumnCount();
                String[] labelNames = new String[columnCount + 1];
                int[] types = new int[columnCount + 1];
                Map<String, Object> map=new HashMap<String, Object>();
                for (int j=1; j<labelNames.length; j++) {

                    labelNames[j] = rsmd.getColumnLabel(j);
                    map.put(labelNames[j],rs.getObject(j));

                }
                list.add(map);
                return null;
            }
        },args);
//        jdbcTemplate.query(sql, new RowMapper<Object>() {
//            @Override
//            public Object mapRow(ResultSet rs, int i) throws SQLException {
//                ResultSetMetaData rsmd = rs.getMetaData();
//
//                int columnCount = rsmd.getColumnCount();
//                String[] labelNames = new String[columnCount + 1];
//                int[] types = new int[columnCount + 1];
//                Map<String, Object> map=new HashMap<String, Object>();
//                for (int j=1; j<labelNames.length; j++) {
//
//                    labelNames[j] = rsmd.getColumnLabel(j);
//                    map.put(labelNames[j],rs.getObject(j));
//
//                }
//                list.add(map);
//                return null;
//            }
//        });
        return list;
    }

    /**
     * hql 参数构造器
     * @param queryString
     * @param values
     * @return
     */
    protected Query createQuery(String queryString, Object... values) {
        Assert.hasText(queryString);
        Query query = getSession().createQuery(queryString).setCacheable(true);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                query.setParameter(i, values[i]);
            }
        }
        return query;
    }
    protected SQLQuery createSQLQuery(String sqlString, Object... values) {
        Assert.hasText(sqlString);
        SQLQuery sqlQuery = getSession().createSQLQuery(sqlString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                sqlQuery.setParameter(i, values[i]);
            }
        }
        return sqlQuery;
    }

    // 查询数据表的数量
    public int countQueryResult(String hql, Object... values) {
        String fromClause = hql.substring(hql.indexOf("from"));
        String countHql = "select count(*) " + fromClause;
        Query query = createQuery(countHql, values);
        return ((Long) query.uniqueResult()).intValue();
    }

    protected <T extends Serializable> Criteria createCriteria(Class<T> entityClass, Criterion... criterions) {
        Criteria crit = getSession().createCriteria(entityClass).setCacheable(true);
        if (criterions != null && criterions.length > 0) {
            for (Criterion c : criterions) {
                crit.add(c);
            }
        }
        return crit;
    }
    @Override
    public <T extends Serializable> List<T> findListByHQL(int pageNo, int pageSize, String hql, Object... values) {
        Pager<T> pager = new Pager<T>(pageNo, pageSize);
        pager= findByHQL(pager,hql,values);
        return pager.getList();
    }
}
